package com.cyy.srv

import com.cyy.model.Constants
import com.cyy.model.GmodelModel
import com.jfinal.kit.Kv
import com.jfinal.plugin.activerecord.generator.Generator
import com.jfinal.plugin.activerecord.generator.MetaBuilder
import com.jfinal.plugin.druid.DruidPlugin
import java.sql.Connection
import tornadofx.*
import java.sql.DriverManager
import java.sql.ResultSet
import javax.sql.DataSource
import com.jfinal.plugin.activerecord.ActiveRecordPlugin
import com.jfinal.plugin.activerecord.Db
import com.jfinal.template.source.FileSourceFactory
import java.io.File


class GenSrv : Controller() {

    val gmodel: GmodelModel by inject()

    lateinit var con: Connection
    lateinit var rs: ResultSet
    var al = ArrayList<String>() // database list

    fun getCon(): Boolean {
        gmodel.jdbcUrl.value = "jdbc:${gmodel.dbtype.value}://${gmodel.host.value}:${gmodel.port.value}"
        Class.forName(gmodel.driver.value)
        try {
            con = DriverManager.getConnection(gmodel.jdbcUrl.value, gmodel.user.value, gmodel.pwd.value)
            return true
        } catch (e: Exception) {
            println("getCon failed ${e}")
            return false
        }
    }

    //    获取数据源
    fun getDataSource(jdbcUrl: String): DataSource {
        val druidPlugin = DruidPlugin(jdbcUrl, gmodel.user.value, gmodel.pwd.value, gmodel.driver.value)
        gmodel.arp.value = ActiveRecordPlugin(druidPlugin)

        gmodel.arp.value.addSqlTemplate(FileSourceFactory().getSource("${File("").canonicalPath}\\doc\\sql", "all.sql", "utf8"))
        druidPlugin.start()
        gmodel.arp.value.start()
        return druidPlugin.getDataSource()
    }

    /**
     * get database list
     * @return ArrayList<String> 数据库名称列表
     */
    fun getDBs(): ArrayList<String> {
        //先清空，再添加获取的数据库列表，避免每次点击重复添加相同的数据库
        if (al.isNotEmpty()) {
            al.clear()
        }

        rs = con.metaData.catalogs
        while (rs.next()) {
            al.add(rs.getString("TABLE_CAT"))
        }
        if (gmodel.dbs.isNotEmpty()) {
            gmodel.dbs.removeAt(0)
        }
        gmodel.dbs.addAll(al)
        return al
    }

    fun gen() {
        // 创建生成器
//        val generator = Generator(ds, bmpkg, bmpkgpath, mpkg, modelOutputDir)
        val generator = Generator(gmodel.dataSource.value, gmodel.bmpkg.value, gmodel.bmpkgpath.value, gmodel.mpkg.value, gmodel.modelOutputDir.value)

        // 配置是否生成备注
        generator.setGenerateRemarks(gmodel.remark.value)
//        generator.setBaseModelTemplate("projects/IdeaProjects/javafx/generator-sqlite/tpl/model_template.jf")
//        generator.setModelTemplate("projects/IdeaProjects/javafx/generator-sqlite/tpl/model_template.jf")
//        generator.setModelTemplate(gmodel.modelTemplate.value)
        generator.setModelTemplate("jfinal/model_template.jf")

        // 设置数据库方言
        generator.setDialect(gmodel.dialect.value)

        // 设置是否生成链式 setter 方法
        generator.setGenerateChainSetter(true)


        // 添加不需要生成的表名
        generator.addExcludedTable("data_dictionary", "data_dictionary_value",
                "file_uploaded", "sys_function", "sys_log", "sys_org",
                "sys_role", "sys_role_function", "sys_user", "sys_user_role")

        // 设置是否在 Model 中生成 dao 对象
        generator.setGenerateDaoInModel(true)

        // 设置是否生成字典文件
        generator.setGenerateDataDictionary(true)

        // 设置需要被移除的表名前缀用于生成modelName。例如表名 "osc_user"，移除前缀 "osc_"后生成的model名为 "User"而非 OscUser
        generator.setRemovedTableNamePrefixes("four100_")

        // 生成
        generator.generate()
    }

    /**
     * get all tables in selected databases for mysql
     * @return ArrayList<String> 选择的数据库中的表名称列表
     */

    fun getList(con:Connection,sql:String):ArrayList<String> {
        val tblList = ArrayList<String>()
        rs = con.prepareStatement(sql).executeQuery()
        while (rs.next()) {
            if (rs.getString(1).isNotEmpty()) {
                tblList.add(rs.getString(1))
            }
        }
        return tblList
    }


    /**
     * 当数据库切换时，得到所选择数据库中的所有表，并将新的jDbPro对象加入到engine的SharedObjectMap中
     */
    fun prapare() {
        // 停止之前的activeRecordPlugin
        if ((gmodel.arp.value != null)) {
            gmodel.arp.value.stop()
        }

        gmodel.jdbcUrl.value = "jdbc:${gmodel.dbtype.value}://${gmodel.host.value}:${gmodel.port.value}/${gmodel.dbname.value}?characterEncoding=utf8&useInformationSchema=true&useSSL=false"

        gmodel.dataSource.value = getDataSource(gmodel.jdbcUrl.value)
        gmodel.metaBuilder.value = MetaBuilder(gmodel.dataSource.value)
        gmodel.metaBuilder.value.setDialect(gmodel.dialect.value)
        gmodel.getTablesSql.value = "select table_name from information_schema.TABLES where TABLE_SCHEMA='${gmodel.dbname.value}'"

        gmodel.tables.clear()

        gmodel.tables.addAll(getList(gmodel.dataSource.value.connection,gmodel.getTablesSql.value))
        Constants.addSharedObject(gmodel.engine.value, Kv.by("Db", Db())
                .set("gmodel", gmodel))
    }
}